package study.cell_game.objects.tokens;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.entity.text.TextOptions;
import org.andengine.util.HorizontalAlign;


import android.graphics.Typeface;

import study.cell_game.activity.GameActivity;
import study.cell_game.enums.Direction;
import study.cell_game.enums.PlayerColor;
import study.cell_game.enums.TokenType;
import study.cell_game.enums.TokenUsageType;
import study.cell_game.objects.Cell;
import study.cell_game.objects.borders.Border;
import study.cell_game.objects.textures.TokenTextures;
import study.cell_game.scenes.GameScene;

public class Token {

	Token(Sprite core, Border border, int tokenDraw, int charges, int chargesMax, TokenLogic logic, int id, boolean usable) {
		this.core = core;
		this.border = border;
		this.tokenDraw = tokenDraw;
		this.charges = charges;
		this.chargesMax = chargesMax;
		this.logic = logic;
		this.id = id;
		this.usable = usable;
	}

	private boolean usable;
	// rdzeń z ikoną; mógłby być definiowany przez tokenLogic ale co tam
	private Sprite core;

	// indywidualna logika update'u dla tego tokena.
	private TokenLogic logic;

	// sprite z kolorem gracza. Muuucho importante.
	private TokenSprite playerColor;

	// sprite granicy oraz dane na jej temat.
	private Border border;
	//private Font font = new Font(this.mFontTexture, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 32, true, Color.BLACK);
	//private Text charg ;//= new Text(0, 0, font , "0123456789", GameActivity.main.getVertexBufferObjectManager());

	// właściciel żetonu
	private PlayerColor owner; // owner of the cell

	// ładunki
	private Integer charges; // number of charges

	// maximum ładunków - pow tego pułapu nie produkuje
	private int chargesMax;
	
	// ID techniczne
	private int id;

	// flaga czy położony.
	private boolean placed = false;

	// text z ilością aktualną ładunków
	private Text centerText;

	// komórka na której stoi
	private Cell cell;

	// jak wpływa na dobieranie tokenów
	private int tokenDraw;
	private Direction preferredDirection;

	public void alignToMax(){
		if(charges > chargesMax) charges = chargesMax;
	}
	
	public void update() {
		if (logic != null) {

			// update z delegaty
			logic.update();
			
			if(charges > chargesMax/2 && this.preferredDirection != null){
				Token tokenAtDir = cell.getNeighbours()[preferredDirection.getValue()].getToken();
				if (tokenAtDir.owner != this.owner) {
					tokenAtDir.attackFor(charges - chargesMax/2, owner);
					charges = chargesMax/2;
				} else if (tokenAtDir.charges < tokenAtDir.chargesMax){
					tokenAtDir.reinforceFor(charges - chargesMax/2, owner);
					charges = chargesMax/2;
				}
				
			}
			
			// logika przesyłu międzyżetonowego
//			if (charges > chargesMax) {
//				List<Direction> dirs = cell.getOutboundDirections();
//				
//				//1. najpierw powinno atakować przeciwników
//				//2. potem powinno zasilać niepełne własne żetony
//				//3. na koniec rozsyłać losowo.
//				
//				List<Direction> enemyDirs = new ArrayList<Direction>();
//				List<Direction> ownFirstDirs = new ArrayList<Direction>();
//				List<Direction> ownSecondDirs = new ArrayList<Direction>();
//				
//				for (Direction d : dirs) {
//					Token tokenAtDir = cell.getNeighbours()[d.getValue()].getToken();
//					if (tokenAtDir.owner != this.owner) {
//						enemyDirs.add(d);
//					} else if (tokenAtDir.charges < tokenAtDir.chargesMax) {
//						ownFirstDirs.add(d);
//					} else {
//						ownSecondDirs.add(d);
//					}
//				}
//				if (dirs.size() > 0) {
//					for(int i = 0; i<charges - chargesMax; i++){
//						if(!enemyDirs.isEmpty()){
//							Direction toSend = enemyDirs.get((int) (Math.random() * enemyDirs.size()));
//							Token tsToken = cell.getNeighbours()[toSend.getValue()].getToken();
//							tsToken.attackFor(1, owner);
//						} else if (!ownFirstDirs.isEmpty()){
//							Direction toSend = ownFirstDirs.get((int) (Math.random() * ownFirstDirs.size()));
//							Token tsToken = cell.getNeighbours()[toSend.getValue()].getToken();
//							tsToken.reinforceFor(1, owner);
//						} else {
//							Direction toSend = ownSecondDirs.get((int) (Math.random() * ownSecondDirs.size()));
//							Token tsToken = cell.getNeighbours()[toSend.getValue()].getToken();
//							tsToken.reinforceFor(1, owner);
//						}
//						charges--;
//					}
//				}
//				
//				/*HashMap<Direction, PlayerColor> dirsByOwner = new HashMap<Direction, PlayerColor>();
//				for (Direction d : dirs) {
//					Token tokenAtDir = cell.getNeighbours()[d.getValue()].getToken();
//					if (tokenAtDir.owner == this.owner) {
//						if (tokenAtDir.charges < tokenAtDir.chargesMax) {
//							dirsByOwner.put(d, tokenAtDir.owner);
//						}
//					} else {
//						dirsByOwner.put(d, tokenAtDir.owner);
//					}
//				}
//				Set<Entry<Direction, PlayerColor>> set = dirsByOwner.entrySet();// .toArray(new
//				// Entry<Direction,
//				// PlayerColor>[dirsByOwner.size()]);
//				Entry<Direction, PlayerColor>[] arr = set.toArray(new Entry[dirsByOwner.size()]);*/
//				//if (arr.length > 0) {
//				/*	 if (dirs.size() > 0) {
//					for (int i = 0; i < charges - chargesMax; i++) {
//						Direction toSend = dirs.get((int) (Math.random() * dirs.size()));
//						//Entry<Direction, PlayerColor> toSend = arr[(int) (Math.random() * (arr.length))];
//						Token tsToken = cell.getNeighbours()[toSend.getValue()].getToken();
//						if (tsToken.getOwner() == this.owner) {
//							tsToken.reinforceFor(1, owner);
//						} else {
//							tsToken.attackFor(1, owner);
//						}
//						charges--;
//					}
//				}*/
//			}
			// charges = chargesMax;
		}

		// update textu
		if (centerText != null) {
			if(charges < 0) charges = 0;
			if(charges > chargesMax) charges = chargesMax;
			centerText.setText(Integer.toString(charges));
		}

	}

	private void reinforceFor(int i, PlayerColor owner2) {
		charges += i;

	}

	private void attackFor(int i, PlayerColor owner) {
		charges -= i;
		if (charges <= 0) {
			this.owner = owner;
			GameScene.getInstance().getMainLayer().detachChild(playerColor);
			playerColor.detachChildren();
			GameScene.getInstance().unregisterTouchArea(playerColor);
			playerColor = new TokenSprite(cell.getX(), cell.getY(), TokenTextures.getInstance()
					.getTokenBackgroundForPlayer(owner), GameActivity.main.getVertexBufferObjectManager(), this);
			GameScene.getInstance().getMainLayer().attachChild(playerColor);
			// GameScene.getInstance().registerTouchArea(playerColor);
			playerColor.attachChild(this.core);
			// Sprite borderSprite = this.border.getActiveSprite();
			// borderSprite.setPosition(0, 0);
			// playerColor.attachChild(borderSprite);
			centerText = new Text(0, 0, GameActivity.main.getFont(), "00", new TextOptions(HorizontalAlign.CENTER),
					GameActivity.main.getVertexBufferObjectManager());
			playerColor.attachChild(centerText);

		}
	}

	public Sprite getCore() {
		return core;
	}

	public PlayerColor getOwner() {
		return owner;
	}

	public void setOwner(PlayerColor owner) {
		this.owner = owner;
	}

	public int getCharges() {
		return charges;

	}

	public int getTokenDraw() {
		return this.tokenDraw;
	}

	public Border getBorder() {
		return border;
	}

	public void startDrawing() {
		playerColor = new TokenSprite(cell.getX(), cell.getY(), TokenTextures.getInstance()
				.getTokenBackgroundForPlayer(owner), GameActivity.main.getVertexBufferObjectManager(), this);

		// Sprite borderSprite = this.border.getActiveSprite();
		// borderSprite.setPosition(0, 0);

		GameScene.getInstance().getMainLayer().attachChild(playerColor);
		GameScene.getInstance().registerTouchArea(playerColor);
		playerColor.attachChild(this.core);
		// playerColor.attachChild(borderSprite);
		centerText = new Text(0, 0, GameActivity.main.getFont(), "00", new TextOptions(HorizontalAlign.CENTER),
				GameActivity.main.getVertexBufferObjectManager());
		centerText.setScale((float)0.5);
		playerColor.attachChild(centerText);
		//charg.setText(charges.toString());
		//playerColor.attachChild(charg);

	}

	public void setCell(Cell cell) {
		this.cell = cell;
	}

	public void setCharges(int charges) {
		this.charges = charges;
	}

	public int getId() {
		return id;
	}

	public Cell getCell() {
		return cell;
	}

	public TokenSprite getPlayerColor() {
		return playerColor;
	}

	public boolean getPlaced() {
		return placed;
	}

	public void setPlaced(boolean placed) {
		this.placed = placed;
	}

	public int getMaxCharges() {
		return chargesMax;
	}
	
	public boolean getUsable() {
		return usable;
	}

	public TokenUsageType getTokenType() {
		return usable ? TokenUsageType.CASTABLE : TokenUsageType.SETTABLE;
	}
	
	public void rotateClockwise(){
		this.core.detachChild(border.getActiveSprite());
		this.border.rotateClockwise();
		this.core.attachChild(border.getActiveSprite());
		this.cell.tokenPlaced();
	}

	public void setPreferredDirection(Direction dir) {
		this.preferredDirection = dir;
	}
	
	public Direction getPreferredDirection(){
		return this.preferredDirection;
	}
}
